home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 May: Tool Chest / Developer CD Series May 1996 (Tool Chest) (Apple Computer) (1996).iso / Tool Chest / Development Tools & Languages / Dylan Related / Mindy / Mindy 1.2 - portable sources / interp / debug.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-15  |  54.9 KB  |  2,424 lines  |  [TEXT/ttxt]

  1. /**********************************************************************\
  2. *
  3. *  Copyright (c) 1994  Carnegie Mellon University
  4. *  All rights reserved.
  5. *  
  6. *  Use and copying of this software and preparation of derivative
  7. *  works based on this software are permitted, including commercial
  8. *  use, provided that the following conditions are observed:
  9. *  
  10. *  1. This copyright notice must be retained in full on any copies
  11. *     and on appropriate parts of any derivative works.
  12. *  2. Documentation (paper or online) accompanying any system that
  13. *     incorporates this software, or any part of it, must acknowledge
  14. *     the contribution of the Gwydion Project at Carnegie Mellon
  15. *     University.
  16. *  
  17. *  This software is made available "as is".  Neither the authors nor
  18. *  Carnegie Mellon University make any warranty about the software,
  19. *  its performance, or its conformity to any specification.
  20. *  
  21. *  Bug reports, questions, comments, and suggestions should be sent by
  22. *  E-mail to the Internet address "gwydion-bugs@cs.cmu.edu".
  23. *
  24. ***********************************************************************
  25. *
  26. * $Header: debug.c,v 1.40 94/11/28 15:48:20 wlott Exp $
  27. *
  28. * This file implements the debugger.
  29. *
  30. \**********************************************************************/
  31.  
  32. #include "../compat/std-c.h"
  33. #include "../compat/std-os.h"
  34.  
  35. #include <setjmp.h>
  36.  
  37. #include "mindy.h"
  38. #include "thread.h"
  39. #include "driver.h"
  40. #include "func.h"
  41. #include "module.h"
  42. #include "str.h"
  43. #include "list.h"
  44. #include "vec.h"
  45. #include "type.h"
  46. #include "sym.h"
  47. #include "num.h"
  48. #include "obj.h"
  49. #include "bool.h"
  50. #include "print.h"
  51. #include "interp.h"
  52. #include "value.h"
  53. #include "error.h"
  54. #include "gc.h"
  55. #include "brkpt.h"
  56. #include "instance.h"
  57. #include "../comp/byteops.h"
  58.  
  59. struct library *CurLibrary = NULL;
  60. struct module *CurModule = NULL;
  61.  
  62. struct frame_info {
  63.     struct frame_info *up;
  64.     struct frame_info *down;
  65.     obj_t *fp;
  66.     obj_t component;
  67.     int pc;
  68.     obj_t source_file;
  69.     obj_t mtime;
  70.     int line;
  71.     obj_t locals;
  72. };
  73.  
  74. static jmp_buf BlowOffCmd;
  75. static struct thread *CurThread = NULL;
  76. static obj_t CurThreadObj = NULL;
  77. static struct frame_info *CurFrame = NULL, *TopFrame = NULL;
  78. static int PrevLine = -1;
  79. static boolean ThreadChanged = FALSE, FrameChanged = FALSE;
  80. static boolean Continue;
  81.  
  82. static obj_t do_eval_func;
  83. static obj_t do_print_func;
  84.  
  85. static struct variable *debugger_eval_var;
  86. static struct variable *debugger_flush_var;
  87. static struct variable *debugger_call_var;
  88. static struct variable *debugger_print_var;
  89. static struct variable *debugger_report_var;
  90. static struct variable *debugger_abort_var;
  91. static struct variable *debugger_restarts_var;
  92. static struct variable *debugger_restart_var;
  93. static struct variable *debugger_return_var;
  94.  
  95.  
  96.  
  97. /* Frame utilities. */
  98.  
  99. static struct frame_info *make_frame(struct frame_info *up, obj_t *fp,
  100.                      obj_t component, int pc)
  101. {
  102.     struct frame_info *res = malloc(sizeof(*res));
  103.     obj_t debug_info;
  104.     int len, i, n_const;
  105.  
  106.     res->up = up;
  107.     res->down = NULL;
  108.     res->fp = fp;
  109.     res->component = component;
  110.     res->pc = pc;
  111.     res->source_file = obj_False;
  112.     res->mtime = make_fixnum(0);
  113.     res->line = 0;
  114.     res->locals = obj_False;
  115.  
  116.     if (obj_is_fixnum(component))
  117.     return res;
  118.  
  119.     res->source_file = COMPONENT(component)->source_file;
  120.     res->mtime = COMPONENT(component)->mtime;
  121.  
  122.     debug_info = COMPONENT(component)->debug_info;
  123.     if (debug_info == obj_False)
  124.     return res;
  125.  
  126.     n_const = COMPONENT(component)->n_constants;
  127.     pc -= (char *)(&COMPONENT(component)->constant[n_const])-(char *)component;
  128.  
  129.     if (pc < 0)
  130.     return res;
  131.  
  132.     len = SOVEC(debug_info)->length;
  133.     for (i = 0; i < len; i++) {
  134.     obj_t entry = SOVEC(debug_info)->contents[i];
  135.     pc -= fixnum_value(SOVEC(entry)->contents[1]);
  136.     if (pc < 0) {
  137.         res->line = fixnum_value(SOVEC(entry)->contents[0]);
  138.         res->locals = SOVEC(entry)->contents[2];
  139.         break;
  140.     }
  141.     }
  142.  
  143.     return res;
  144. }
  145.  
  146. static struct frame_info *top_frame(struct thread *thread)
  147. {
  148.     if (thread)
  149.     return make_frame(NULL, thread->fp, thread->component, thread->pc);
  150.     else
  151.     return NULL;
  152. }
  153.  
  154. static struct frame_info *frame_down(struct frame_info *frame)
  155. {
  156.     if (frame->down != NULL)
  157.     return frame->down;
  158.     else {
  159.     obj_t *fp = frame->fp;
  160.     obj_t *old_fp = obj_rawptr(fp[-4]);
  161.  
  162.     if (old_fp) {
  163.         frame->down = make_frame(frame, old_fp, fp[-2],
  164.                      fixnum_value(fp[-1]));
  165.         return frame->down;
  166.     }
  167.     else
  168.         return NULL;
  169.     }
  170. }
  171.  
  172. static struct frame_info *frame_up(struct frame_info *frame)
  173. {
  174.     return frame->up;
  175. }
  176.  
  177. static void free_frames(struct frame_info *frame)
  178. {
  179.     struct frame_info *next;
  180.  
  181.     while (frame) {
  182.     next = frame->down;
  183.     free(frame);
  184.     if (frame == CurFrame)
  185.         CurFrame = NULL;
  186.     frame = next;
  187.     }
  188. }
  189.  
  190. static void scav_frames(struct frame_info *frame)
  191. {
  192.     while (frame != NULL) {
  193.     scavenge(&frame->component);
  194.     scavenge(&frame->source_file);
  195.     scavenge(&frame->mtime);
  196.     scavenge(&frame->locals);
  197.     frame = frame->down;
  198.     }
  199. }
  200.  
  201. static void print_frame(struct frame_info *frame, boolean print_line)
  202. {
  203.     obj_t *ptr = obj_rawptr(frame->fp[-3]);
  204.     obj_t *end = frame->fp - 4;
  205.     obj_t name = function_debug_name_or_self(*ptr++);
  206.  
  207.     printf("fp 0x%08lx: ", (unsigned long)frame->fp);
  208.     if (object_class(name) == obj_SymbolClass)
  209.     fputs(sym_name(name), stdout);
  210.     else
  211.     prin1(name);
  212.     putchar('(');
  213.     if (ptr < end) {
  214.     while (1) {
  215.         prin1(*ptr++);
  216.         if (ptr >= end)
  217.         break;
  218.         printf(", ");
  219.     }
  220.     }
  221.     if (frame->source_file == obj_False || !print_line)
  222.     printf(")\n");
  223.     else {
  224.     printf(") [%s", string_chars(frame->source_file));
  225.     if (frame->line == 0)
  226.         printf("]\n");
  227.     else
  228.         printf(", line %d]\n", frame->line);
  229.     }
  230. }
  231.  
  232. static void set_frame(struct frame_info *frame)
  233. {
  234.     if (CurFrame == NULL || frame == NULL || CurFrame->fp != frame->fp) {
  235.     FrameChanged = TRUE;
  236.     PrevLine = -1;
  237.     }
  238.  
  239.     CurFrame = frame;
  240. }
  241.  
  242.  
  243.  
  244. /* Thread utilities. */
  245.  
  246. static void set_thread(struct thread *thread)
  247. {
  248.     CurThread = thread;
  249.     if (thread != NULL)
  250.     CurThreadObj = thread->thread_obj;
  251.     else
  252.     CurThreadObj = NULL;
  253.     ThreadChanged = TRUE;
  254.     free_frames(TopFrame);
  255.     TopFrame = top_frame(thread);
  256.     set_frame(TopFrame);
  257. }
  258.  
  259. static void print_thread(struct thread *thread)
  260. {
  261.     static char *status_chars = {"RSDBW"};
  262.     printf("[%d] %c ", thread->id, status_chars[(int)thread->status]);
  263.     if (thread->suspend_count != 0)
  264.     printf("%d ", thread->suspend_count);
  265.     else
  266.     printf("  ");
  267.     if (THREAD(thread->thread_obj)->debug_name != obj_False)
  268.     print(THREAD(thread->thread_obj)->debug_name);
  269.     else
  270.     putchar('\n');
  271. }
  272.  
  273. static void suspend_other_threads(struct thread *thread)
  274. {
  275.     struct thread_list *threads;
  276.  
  277.     for (threads = all_threads(); threads != NULL; threads = threads->next)
  278.     if (threads->thread != thread)
  279.         thread_suspend(threads->thread);
  280. }
  281.  
  282. static void restart_other_threads(struct thread *thread)
  283. {
  284.     struct thread_list *threads;
  285.  
  286.     for (threads = all_threads(); threads != NULL; threads = threads->next)
  287.     if (threads->thread != thread)
  288.         thread_restart(threads->thread);
  289. }
  290.  
  291. static void kill_me(struct thread *thread, obj_t *vals)
  292. {
  293.     thread_kill(thread);
  294.     restart_other_threads(NULL);
  295.     set_thread(NULL);
  296.     pause(pause_DebuggerCommandFinished);
  297. }
  298.  
  299. static void debugger_cmd_finished(struct thread *thread, obj_t *vals)
  300. {
  301.     thread->sp = vals;
  302.     thread_pop_escape(thread);
  303.     restart_other_threads(thread);
  304.     pause(pause_DebuggerCommandFinished);
  305. }
  306.  
  307. static void validate_thread_and_frame()
  308. {
  309.     if (CurThread != NULL) {
  310.     if (THREAD(CurThreadObj)->thread == NULL) {
  311.         printf("Current thread no longer exists.\n");
  312.         set_thread(NULL);
  313.         ThreadChanged = FALSE;
  314.         FrameChanged = FALSE;
  315.         return;
  316.     }
  317.  
  318.     if (TopFrame == NULL) {
  319.         if (CurThread->fp != NULL) {
  320.         TopFrame = top_frame(CurThread);
  321.         set_frame(TopFrame);
  322.         }
  323.     }
  324.     else {
  325.         if (CurThread->fp != TopFrame->fp
  326.           || CurThread->component != TopFrame->component
  327.           || CurThread->pc != TopFrame->pc) {
  328.         struct frame_info *old_top = TopFrame;
  329.         TopFrame = top_frame(CurThread);
  330.         set_frame(TopFrame);
  331.         free_frames(old_top);
  332.         }
  333.     }
  334.     }
  335. }
  336.  
  337.  
  338. /* Source code stuff. */
  339.  
  340. static obj_t cur_source_file = NULL;
  341. static time_t cur_mtime = 0;
  342. static FILE *cur_source_stream = NULL;
  343. static long *line_offsets = NULL;
  344. static int lines_alloced = 0;
  345. static int lines_found = 0;
  346. static char **source_directories = NULL;
  347.  
  348. static FILE *find_source_line(obj_t file, obj_t mtime, int line)
  349. {
  350.     int c;
  351.  
  352.     if (file == obj_False)
  353.     return NULL;
  354.  
  355.     if (file != cur_source_file) {
  356.     char *name = (char *)string_chars(file);
  357.  
  358.     if (cur_source_stream != NULL) {
  359.         fclose(cur_source_stream);
  360.         cur_source_stream = NULL;
  361.     }
  362.     
  363.     if (source_directories == NULL || name[0] == '/')
  364.         cur_source_stream = fopen(name, "r");
  365.     else
  366.         cur_source_stream = NULL;
  367.  
  368.     cur_source_file = file;
  369.     cur_mtime = 0;
  370.     if (line_offsets == NULL) {
  371.         lines_alloced = 1000;
  372.         line_offsets = malloc(sizeof(long) * lines_alloced);
  373.         line_offsets[0] = 0;
  374.         line_offsets[1] = 0;
  375.     }
  376.     lines_found = 1;
  377.     }
  378.  
  379.     if (cur_source_stream == NULL)
  380.     return NULL;
  381.  
  382.     if (cur_mtime == 0) {
  383.     struct stat buf;
  384.  
  385.     fstat(fileno(cur_source_stream), &buf);
  386.  
  387.     cur_mtime = buf.st_mtime;
  388.     }
  389.  
  390.     if (cur_mtime != fixnum_value(mtime))
  391.     printf("\nWarning: %s has changed", string_chars(file));
  392.  
  393.     if (line > lines_found) {
  394.     fseek(cur_source_stream, line_offsets[lines_found], 0);
  395.     while ((c = getc(cur_source_stream)) != EOF) {
  396.         if (c == '\n') {
  397.         lines_found++;
  398.         if (lines_found >= lines_alloced) {
  399.             lines_alloced *= 2;
  400.             line_offsets = realloc(line_offsets,
  401.                        sizeof(long) * lines_alloced);
  402.         }
  403.         line_offsets[lines_found] = ftell(cur_source_stream);
  404.         if (lines_found == line)
  405.             break;
  406.         }
  407.     }
  408.     }
  409.     else
  410.     fseek(cur_source_stream, line_offsets[line], 0);
  411.  
  412.     return cur_source_stream;
  413. }
  414.  
  415.  
  416.  
  417. /* Stuff to explain the reason why we dropped into the debugger. */
  418.  
  419. static void explain_condition(struct thread *thread, obj_t condition)
  420. {
  421.     if (instancep(condition, obj_SimpleObjectVectorClass)) {
  422.     char *fmt = (char *)string_chars(SOVEC(condition)->contents[0]);
  423.  
  424.     putchar('\n');
  425.     vformat(fmt, SOVEC(condition)->contents+1, SOVEC(condition)->length-1);
  426.     printf("\n\n");
  427.     }
  428.     else if (debugger_report_var == NULL
  429.          || debugger_report_var->value == obj_Unbound) {
  430.     printf("\ninvoke-debugger called from dylan.  Condition = ");
  431.     print(condition);
  432.     putchar('\n');
  433.     }
  434.     else {
  435.     thread_push_escape(thread);
  436.     set_c_continuation(thread, debugger_cmd_finished);
  437.  
  438.     suspend_other_threads(thread);
  439.  
  440.     *thread->sp++ = debugger_report_var->value;
  441.     *thread->sp++ = condition;
  442.     thread_restart(thread);
  443.     Continue = TRUE;
  444.     }
  445. }
  446.  
  447. static void explain_debugger_invocation(void)
  448. {
  449.     struct thread *thread = thread_current();
  450.  
  451.     set_thread(thread);
  452.  
  453.     if (thread == NULL) {
  454.     printf("Debugger explicitly invoked, but no current thread?\n");
  455.     ThreadChanged = FALSE;
  456.     FrameChanged = FALSE;
  457.     return;
  458.     }
  459.  
  460.     if (thread->status != status_Debuggered) {
  461.     printf("Debugger explicitly invoked, but not by current thread?\n");
  462.     return;
  463.     }
  464.  
  465.     explain_condition(thread, thread->datum);
  466. }
  467.  
  468. static void explain_reason(enum pause_reason reason)
  469. {
  470.     switch (reason) {
  471.       case pause_NoReason:
  472.       case pause_PickNewThread:
  473.       case pause_DebuggerCommandFinished:
  474.     validate_thread_and_frame();
  475.     break;
  476.       case pause_NothingToRun:
  477.     printf("All threads exited.\n");
  478.     set_thread(NULL);
  479.     ThreadChanged = FALSE;
  480.     FrameChanged = FALSE;
  481.     break;
  482.       case pause_Interrupted:
  483.     printf("Interrupted\n");
  484.     set_thread(thread_current());
  485.     break;
  486.       case pause_DebuggerInvoked:
  487.     explain_debugger_invocation();
  488.     break;
  489.       case pause_HitBreakpoint:
  490.     printf("Breakpoint\n");
  491.     set_thread(thread_current());
  492.     break;
  493.     }
  494. }
  495.  
  496.  
  497. /* Command tables. */
  498.  
  499. struct cmd_entry {
  500.     char *cmd;
  501.     char *help;
  502.     void (*fn)(obj_t args);
  503. };
  504.  
  505. static struct cmd_entry *find_cmd(obj_t cmd_name, struct cmd_entry *table, char *what)
  506. {
  507.     struct cmd_entry *match = NULL;
  508.     char *text = sym_name(cmd_name);
  509.     int leng = strlen(text);
  510.  
  511.     while (table->cmd) {
  512.     if (strncasecmp(table->cmd, text, leng) == 0) {
  513.         if (strlen(table->cmd) == leng)
  514.         return table;
  515.         if (match) {
  516.         printf("ambiguous %s, could be either ``%s'' or ``%s''\n",
  517.                what, match->cmd, table->cmd);
  518.         return NULL;
  519.         }
  520.         match = table;
  521.     }
  522.     table++;
  523.     }
  524.  
  525.     if (match == NULL)
  526.     printf("unknown %s\n", what);
  527.  
  528.     return match;
  529. }
  530.  
  531.  
  532. /* Argument list hacking */
  533. static obj_t arg_kind(obj_t arg)
  534. {
  535.     return HEAD(arg);
  536. }
  537. static obj_t arg_value(obj_t arg)
  538. {
  539.     return TAIL(arg);
  540. }
  541. static int any_args(obj_t args)
  542. {
  543.     return args != obj_Nil;
  544. }
  545. static obj_t first_arg(obj_t args)
  546. {
  547.     return HEAD(args);
  548. }
  549. static obj_t rest_args(obj_t args)
  550. {
  551.     return TAIL(args);
  552. }
  553. static int get_fixnum(obj_t obj, int *num)
  554. {
  555.     if (obj != obj_Nil
  556.      && arg_kind(obj) == symbol("literal")
  557.      && instancep(arg_value(obj), obj_FixnumClass)) {
  558.         *num = fixnum_value(arg_value(obj));
  559.     return 1;
  560.     }
  561.     return 0;
  562. }
  563. static int get_symbol(obj_t obj, obj_t *sym)
  564. {
  565.     if (obj != obj_Nil
  566.      && arg_kind(obj) == symbol("literal")
  567.      && instancep(arg_value(obj), obj_SymbolClass)) {
  568.         *sym = arg_value(obj);
  569.     return 1;
  570.     }
  571.     return 0;
  572. }
  573. static int get_string(obj_t obj, obj_t *str)
  574. {
  575.     if (obj != obj_Nil
  576.      && arg_kind(obj) == symbol("literal")
  577.      && instancep(arg_value(obj), obj_ByteStringClass)) {
  578.         *str = arg_value(obj);
  579.     return 1;
  580.     }
  581.     return 0;
  582. }
  583. static int get_variable(obj_t obj, obj_t *sym)
  584. {
  585.     if (obj != obj_Nil
  586.      && arg_kind(obj) == symbol("variable")
  587.      && instancep(arg_value(obj), obj_SymbolClass)) {
  588.         *sym = arg_value(obj);
  589.     return 1;
  590.     }
  591.     return 0;
  592. }
  593. static int get_name(obj_t obj, char **name)
  594. {
  595.     obj_t named;
  596.     if (get_symbol(obj, &named)
  597.      || get_variable(obj, &named)) {
  598.         *name = sym_name(named);
  599.     return 1;
  600.     }
  601.     if (get_string(obj, &named)) {
  602.         *name = (char *)string_chars(named);
  603.     return 1;
  604.     }
  605.     return 0;
  606. }
  607. static void should_be_no_args(obj_t args)
  608. {
  609.     if (any_args(args))
  610.         printf("superfluous arguments ignored\n");
  611. }
  612.  
  613.  
  614. /* Generic Commands */
  615.  
  616. static void quit_cmd(obj_t args)
  617. {
  618.     should_be_no_args(args);
  619.     exit(0);
  620. }
  621.  
  622. static void continue_cmd(obj_t args)
  623. {
  624.     struct thread_list *threads;
  625.  
  626.     should_be_no_args(args);
  627.     for (threads = all_threads(); threads != NULL; threads = threads->next) {
  628.     enum thread_status status = threads->thread->status;
  629.  
  630.     if (status == status_Running || status == status_Waiting) {
  631.         Continue = TRUE;
  632.         return;
  633.     }
  634.     }
  635.  
  636.     printf("No threads are potentially runnable.\n");
  637. }
  638.  
  639. static void tron_cmd(obj_t args)
  640. {
  641.     extern boolean Tracing;
  642.     should_be_no_args(args);
  643.     Tracing = TRUE;
  644. }
  645.  
  646. static void troff_cmd(obj_t args)
  647. {
  648.     extern boolean Tracing;
  649.     should_be_no_args(args);
  650.     Tracing = FALSE;
  651. }
  652.  
  653. static void gc_cmd(obj_t args)
  654. {
  655.     should_be_no_args(args);
  656.     collect_garbage();
  657. }
  658.  
  659. static void error_cmd(obj_t args)
  660. {
  661.     should_be_no_args(args);
  662.     if (CurThread == NULL)
  663.     printf("No current thread.\n");
  664.     else if (CurThread->status != status_Debuggered)
  665.     printf("The current thread did not stop due to an error.\n");
  666.     else
  667.     explain_condition(CurThread, CurThread->datum);
  668. }
  669.  
  670. static void help_cmd(obj_t args);
  671.  
  672. /* Frame manipulation commands. */
  673.  
  674. static void down_cmd(obj_t args)
  675. {
  676.     should_be_no_args(args);
  677.     if (CurThread == NULL)
  678.     printf("No current thread.\n");
  679.     else if (CurFrame == NULL)
  680.     printf("The current thread has nothing on the stack.\n");
  681.     else {
  682.     struct frame_info *down = frame_down(CurFrame);
  683.  
  684.     if (down != NULL)
  685.         set_frame(down);
  686.     else
  687.         printf("Already at the bottom of the stack.\n");
  688.     }
  689. }
  690.  
  691. static void up_cmd(obj_t args)
  692. {
  693.     should_be_no_args(args);
  694.     if (CurThread == NULL)
  695.     printf("No current thread.\n");
  696.     else if (CurFrame == NULL)
  697.     printf("The current thread has nothing on the stack.\n");
  698.     else {
  699.     struct frame_info *up = frame_up(CurFrame);
  700.  
  701.     if (up != NULL)
  702.         set_frame(up);
  703.     else
  704.         printf("Already at the top of the stack.\n");
  705.     }
  706. }
  707.  
  708. static void frame_cmd(obj_t args)
  709. {
  710.     if (CurThread == NULL)
  711.     printf("No current thread.\n");
  712.     else if (TopFrame == NULL)
  713.     printf("The current thread has nothing on the stack.\n");
  714.     else {
  715.         int num;
  716.     if ( ! any_args(args))
  717.         FrameChanged = TRUE;
  718.     else if ( ! get_fixnum(first_arg(args), &num))
  719.         printf("Bogus frame number, should be an integer.\n");
  720.     else if (num < 0)
  721.         printf("Bogus frame number, should be >= 0.\n");
  722.     else {
  723.         struct frame_info *frame = TopFrame;
  724.         int i;
  725.  
  726.         should_be_no_args(rest_args(args));
  727.         for (i = 0; frame != NULL && i < num; i++)
  728.             frame = frame_down(frame);
  729.  
  730.         if (frame == NULL)
  731.             printf("Frame number too large, should be < %d.\n", i);
  732.         else {
  733.             set_frame(NULL);
  734.         set_frame(frame);
  735.         }
  736.     }
  737.     }
  738. }
  739.  
  740. static boolean backtrace_punted;
  741.  
  742. static void punt_backtrace(void)
  743. {
  744.     backtrace_punted = TRUE;
  745. }
  746.  
  747. static void backtrace_cmd(obj_t args)
  748. {
  749.     should_be_no_args(args);
  750.     if (CurThread == NULL)
  751.     printf("No current thread.\n");
  752.     else {
  753.     struct frame_info *frame;
  754.     
  755.     backtrace_punted = FALSE;
  756.     set_interrupt_handler(punt_backtrace);
  757.  
  758.     for (frame = TopFrame; frame != NULL; frame = frame_down(frame)) {
  759.         if (backtrace_punted) {
  760.         printf("interrupted\n");
  761.         break;
  762.         }
  763.         print_frame(frame, TRUE);
  764.     }
  765.  
  766.     clear_interrupt_handler();
  767.     }
  768. }
  769.  
  770.  
  771. /* Library/module/variable manipulation commands. */
  772.  
  773. static void library_cmd(obj_t args)
  774. {
  775.     struct library *lib;
  776.     obj_t sym;
  777.  
  778.     if ( ! any_args(args)) {
  779.     list_libraries();
  780.     putchar('\n');
  781.     if (CurLibrary) {
  782.         format("Current library is %s\n", library_name(CurLibrary));
  783.     }
  784.     else
  785.         printf("No library currently selected\n");
  786.     } else if (get_symbol(first_arg(args), &sym)
  787.         || get_variable(first_arg(args), &sym)) {
  788.         should_be_no_args(rest_args(args));
  789.     lib = find_library(sym, FALSE);
  790.     if (lib) {
  791.         CurLibrary = lib;
  792.         CurModule = find_module(lib, symbol("Dylan-User"), FALSE, FALSE);
  793.     }
  794.     else {
  795.         printf("No library named ");
  796.         print(sym);
  797.     }
  798.     } else {
  799.     printf("Syntax error.\n");
  800.     }
  801. }
  802.  
  803. static void module_cmd(obj_t args)
  804. {
  805.     struct module *module;
  806.     obj_t sym;
  807.  
  808.     if (CurLibrary == NULL) {
  809.     printf("No library currently selected.\n");
  810.     return;
  811.     }
  812.  
  813.     if ( ! any_args(args)) {
  814.     list_modules(CurLibrary);
  815.     putchar('\n');
  816.     if (CurModule)
  817.         format("The current module is %s\n", module_name(CurModule));
  818.     else
  819.         printf("No module currently selected.\n");
  820.     } else if (get_symbol(first_arg(args), &sym)
  821.         || get_variable(first_arg(args), &sym)) {
  822.         should_be_no_args(rest_args(args));
  823.     module = find_module(CurLibrary, sym, FALSE, FALSE);
  824.     if (module)
  825.         CurModule = module;
  826.     else {
  827.         printf("No module named ");
  828.         print(sym);
  829.     }
  830.     } else {
  831.         printf("Syntax error.\n");
  832.     }
  833. }
  834.  
  835.  
  836. /* Locals command. */
  837.  
  838. static void locals_cmd(obj_t args)
  839. {
  840.     obj_t locals;
  841.  
  842.     should_be_no_args(args);
  843.     if (CurFrame == NULL) {
  844.     printf("No current frame.\n");
  845.     return;
  846.     }
  847.  
  848.     locals = CurFrame->locals;
  849.     if (locals == obj_False) {
  850.     printf("No debug info for this frame.\n");
  851.     return;
  852.     }
  853.  
  854.     while (locals != obj_Nil) {
  855.     obj_t vec = HEAD(locals);
  856.     int len = SOVEC(vec)->length;
  857.     int i;
  858.  
  859.     for (i = 0; i < len; i++) {
  860.         obj_t entry = SOVEC(vec)->contents[i];
  861.         obj_t symbol = SOVEC(entry)->contents[0];
  862.         int loc_info = fixnum_value(SOVEC(entry)->contents[1]);
  863.         boolean indirect = loc_info & 2;
  864.         boolean argument = loc_info & 1;
  865.         int offset = loc_info >> 2;
  866.         obj_t value;
  867.  
  868.         if (argument)
  869.         value = CurFrame->fp[-offset-5];
  870.         else
  871.         value = CurFrame->fp[offset];
  872.         if (indirect)
  873.         value = value_cell_ref(value);
  874.  
  875.         format("%s: %=\n", symbol, value);
  876.     }
  877.  
  878.     locals = TAIL(locals);
  879.     }
  880. }
  881.  
  882.  
  883.  
  884. /* Flush command. */
  885.  
  886. static void flush_cmd(obj_t args)
  887. {
  888.     struct thread *thread;
  889.  
  890.     should_be_no_args(args);
  891.     if (debugger_flush_var == NULL
  892.       || debugger_flush_var->value == obj_Unbound) {
  893.     printf("debugger-flush undefined.\n");
  894.     return;
  895.     }
  896.  
  897.     if ((thread = CurThread) == NULL) {
  898.     thread = thread_create(make_byte_string("debugger flush cmd"));
  899.     set_c_continuation(thread, kill_me);
  900.     }
  901.  
  902.     thread_push_escape(thread);
  903.     set_c_continuation(thread, debugger_cmd_finished);
  904.     
  905.     suspend_other_threads(thread);
  906.     
  907.     *thread->sp++ = debugger_flush_var->value;
  908.     thread_restart(thread);
  909.     Continue = TRUE;
  910. }
  911.  
  912.  
  913.  
  914. /* print command. */
  915.  
  916. static void eval_vars(obj_t expr, boolean *okay, boolean *simple)
  917. {
  918.     obj_t kind = arg_kind(expr);
  919.  
  920.     if (kind == symbol("literal")) {
  921.     /* Don't have to do anything for literals. */
  922.     }
  923.     else if (kind == symbol("variable")) {
  924.     /* Variable reference. */
  925.     obj_t name = arg_value(expr);
  926.     if (CurFrame != NULL && CurFrame->locals != obj_False) {
  927.         obj_t list = CurFrame->locals;
  928.         while (list != obj_Nil) {
  929.         obj_t vec = HEAD(list);
  930.         int len = SOVEC(vec)->length;
  931.         int i;
  932.         for (i = 0; i < len; i++) {
  933.             obj_t entry = SOVEC(vec)->contents[i];
  934.             if (SOVEC(entry)->contents[0] == name) {
  935.             int loc_info = fixnum_value(SOVEC(entry)->contents[1]);
  936.             boolean indirect = loc_info & 2;
  937.             boolean argument = loc_info & 1;
  938.             int offset = loc_info >> 2;
  939.             obj_t value;
  940.  
  941.             if (argument)
  942.                 value = CurFrame->fp[-offset-5];
  943.             else
  944.                 value = CurFrame->fp[offset];
  945.             if (indirect)
  946.                 value = value_cell_ref(value);
  947.             HEAD(expr) = symbol("literal");
  948.             TAIL(expr) = value;
  949.             return;
  950.             }
  951.         }
  952.         list = TAIL(list);
  953.         }
  954.     }
  955.     if (CurModule == NULL) {
  956.         if (*okay) {
  957.         printf("No module currently selected\n");
  958.         *okay = FALSE;
  959.         }
  960.     }
  961.     else {
  962.         struct variable *var = find_variable(CurModule, name,
  963.                          FALSE, FALSE);
  964.         if (var == NULL) {
  965.         printf("no variable named %s in module %s\n",
  966.                sym_name(name),
  967.                sym_name(module_name(CurModule)));
  968.         *okay = FALSE;
  969.         }
  970.         else {
  971.         obj_t value = var->value;
  972.         if (value == obj_Unbound) {
  973.             printf("variable %s in module %s is unbound\n",
  974.                sym_name(name), sym_name(module_name(CurModule)));
  975.             *okay = FALSE;
  976.         }
  977.         else {
  978.             HEAD(expr) = symbol("literal");
  979.             TAIL(expr) = value;
  980.         }
  981.         }
  982.     }
  983.     }
  984.     else if (kind == symbol("debug-var"))
  985.     *simple = FALSE;
  986.     else if (kind == symbol("arg")) {
  987.     if (CurFrame == NULL)  {
  988.         printf("No current frame.\n");
  989.         *okay = FALSE;
  990.     }
  991.     else {
  992.         obj_t *fp = CurFrame->fp;
  993.         obj_t *args = ((obj_t *)obj_rawptr(fp[-3])) + 1;
  994.         int nargs = fp - args - 4;
  995.         int arg = fixnum_value(arg_value(expr));
  996.  
  997.         if (arg >= nargs) {
  998.         printf("%d too large -- Only %d argument%s\n", arg, nargs,
  999.                nargs == 1 ? "" : "s");
  1000.         *okay = FALSE;
  1001.         }
  1002.         else {
  1003.         HEAD(expr) = symbol("literal");
  1004.         TAIL(expr) = args[arg];
  1005.         }
  1006.     }
  1007.     }
  1008.     else if (kind == symbol("funcall")) {
  1009.     obj_t args;
  1010.  
  1011.     for (args = rest_args(expr); args != obj_Nil; args = rest_args(args))
  1012.         eval_vars(first_arg(args), okay, simple);
  1013.     
  1014.     *simple = FALSE;
  1015.     }
  1016.     else
  1017.     lose("Parser returned something strange.");
  1018. }
  1019.  
  1020. static void do_eval(struct thread *thread, obj_t args, int nargs);
  1021. static void do_more_prints(struct thread *thread, obj_t exprs);
  1022.  
  1023. static void eval_return(struct thread *thread, obj_t *vals)
  1024. {
  1025.     do_return(thread, pop_linkage(thread), vals);
  1026. }
  1027.  
  1028. static void continue_eval(struct thread *thread, obj_t *vals)
  1029. {
  1030.     obj_t args = vals[-2];
  1031.     int nargs = fixnum_value(vals[-1]);
  1032.  
  1033.     vals[-2] = vals[0];
  1034.     thread->sp = vals - 1;
  1035.  
  1036.     do_eval(thread, args, nargs);
  1037. }
  1038.  
  1039. static void do_eval(struct thread *thread, obj_t args, int nargs)
  1040. {
  1041.     while (args != obj_Nil) {
  1042.     obj_t arg = first_arg(args);
  1043.     obj_t kind = arg_kind(arg);
  1044.  
  1045.     if (kind == symbol("literal")) {
  1046.         *thread->sp++ = arg_value(arg);
  1047.         nargs++;
  1048.     }
  1049.     else if (kind == symbol("funcall")) {
  1050.         *thread->sp++ = rest_args(args);
  1051.         *thread->sp++ = make_fixnum(nargs+1);
  1052.         *thread->sp++ = do_eval_func;
  1053.         *thread->sp++ = arg_value(arg);
  1054.         set_c_continuation(thread, continue_eval);
  1055.         invoke(thread, 1);
  1056.         return;
  1057.     }
  1058.     else
  1059.         lose("Print command found a strange expression.");
  1060.     args = rest_args(args);
  1061.     }
  1062.     /* One of the ``args'' is the function. */
  1063.     check_type(thread->sp[-nargs], obj_FunctionClass);
  1064.     set_c_continuation(thread, eval_return);
  1065.     invoke(thread, nargs-1);
  1066. }
  1067.  
  1068. static void do_eval_start(struct thread *thread, int nargs)
  1069. {
  1070.     obj_t *args = thread->sp - 1;
  1071.     obj_t eval_args = args[0];
  1072.  
  1073.     assert(nargs == 1);
  1074.  
  1075.     push_linkage(thread, args);
  1076.     do_eval(thread, eval_args, 0);
  1077. }
  1078.  
  1079. static void do_print(struct thread *thread, obj_t *vals)
  1080. {
  1081.     obj_t *old_sp = vals - 1;
  1082.     obj_t exprs = *old_sp;
  1083.  
  1084.     if (vals == thread->sp)
  1085.     printf("[returned 0 values]\n");
  1086.     else {
  1087.     while (1) {
  1088.         prin1(*vals++);
  1089.         if (vals < thread->sp)
  1090.         printf(", ");
  1091.         else {
  1092.         putchar('\n');
  1093.         break;
  1094.         }
  1095.     }
  1096.     }
  1097.  
  1098.     thread->sp = old_sp;
  1099.  
  1100.     do_more_prints(thread, exprs);
  1101. }
  1102.  
  1103. static void do_more_prints(struct thread *thread, obj_t exprs)
  1104. {
  1105.     while (exprs != obj_Nil) {
  1106.     obj_t expr = first_arg(exprs);
  1107.     obj_t kind = arg_kind(expr);
  1108.  
  1109.     if (kind == symbol("literal")) {
  1110.         print(arg_value(expr));
  1111.     }
  1112.     else if (kind == symbol("funcall")) {
  1113.         *thread->sp++ = rest_args(exprs);
  1114.         *thread->sp++ = do_eval_func;
  1115.         *thread->sp++ = arg_value(expr);
  1116.         set_c_continuation(thread, do_print);
  1117.         invoke(thread, 1);
  1118.         return;
  1119.     }
  1120.     else
  1121.         lose("Print command found a strange expression.");
  1122.     }
  1123.  
  1124.     {
  1125.     obj_t *old_sp = pop_linkage(thread);
  1126.     thread->sp = old_sp;
  1127.     do_return(thread, old_sp, old_sp);
  1128.     }
  1129. }
  1130.  
  1131. static void do_print_start(struct thread *thread, int nargs)
  1132. {
  1133.     obj_t *args = thread->sp - 1;
  1134.  
  1135.     assert(nargs == 1);
  1136.  
  1137.     push_linkage(thread, args);
  1138.     do_more_prints(thread, args[0]);
  1139. }
  1140.  
  1141. static void call_or_print(struct variable *var, obj_t args)
  1142. {
  1143.     obj_t exprs = args;
  1144.     boolean okay = TRUE;
  1145.     boolean simple = TRUE;
  1146.     obj_t expr;
  1147.     struct thread *thread;
  1148.  
  1149.     if (exprs == obj_False) {
  1150.     printf("Invalid expression.\n");
  1151.     return;
  1152.     }
  1153.     if (exprs == obj_Nil) {
  1154.     printf("No expression.\n");
  1155.     return;
  1156.     }
  1157.  
  1158.     for (expr = exprs; expr != obj_Nil; expr = rest_args(expr))
  1159.     eval_vars(first_arg(expr), &okay, &simple);
  1160.  
  1161.     if (!okay)
  1162.     return;
  1163.  
  1164.     if (simple && (var == NULL || var->value == obj_Unbound)) {
  1165.     for (expr = exprs; expr != obj_Nil; expr = rest_args(expr))
  1166.         print(arg_value(first_arg(expr)));
  1167.     return;
  1168.     }
  1169.  
  1170.     if (CurThread == NULL) {
  1171.     thread = thread_create(var ? var->name : obj_False);
  1172.     set_c_continuation(thread, kill_me);
  1173.     }
  1174.     else {
  1175.     thread = CurThread;
  1176.     thread_push_escape(thread);
  1177.     set_c_continuation(thread, debugger_cmd_finished);
  1178.     }
  1179.  
  1180.     suspend_other_threads(thread);
  1181.  
  1182.     if (var == NULL || var->value == obj_Unbound)
  1183.     *thread->sp++ = do_print_func;
  1184.     else
  1185.     *thread->sp++ = var->value;
  1186.     *thread->sp++ = exprs;
  1187.  
  1188.     thread_restart(thread);
  1189.     Continue = TRUE;
  1190. }
  1191.  
  1192.  
  1193. static void call_cmd(obj_t args)
  1194. {
  1195.     call_or_print(debugger_call_var, args);
  1196. }
  1197.  
  1198. static void print_cmd(obj_t args)
  1199. {
  1200.     call_or_print(debugger_print_var, args);
  1201. }
  1202.  
  1203.  
  1204. /* Restart commands. */
  1205.  
  1206. static void abort_cmd(obj_t args)
  1207. {
  1208.     struct thread *thread;
  1209.  
  1210.     should_be_no_args(args);
  1211.     if (debugger_abort_var == NULL
  1212.       || debugger_abort_var->value == obj_Unbound) {
  1213.     printf("debugger-abort undefined.\n");
  1214.     return;
  1215.     }
  1216.  
  1217.     if ((thread = CurThread) == NULL) {
  1218.     printf("No current thread.\n");
  1219.     return;
  1220.     }
  1221.  
  1222.     thread_push_escape(thread);
  1223.     set_c_continuation(thread, debugger_cmd_finished);
  1224.     
  1225.     suspend_other_threads(thread);
  1226.     
  1227.     *thread->sp++ = debugger_abort_var->value;
  1228.     thread_restart(thread);
  1229.     Continue = TRUE;
  1230. }
  1231.  
  1232. static void describe_restarts(void)
  1233. {
  1234.     obj_t cond;
  1235.     struct thread *thread;
  1236.  
  1237.     if (debugger_restarts_var == NULL
  1238.       || debugger_restarts_var->value == obj_Unbound) {
  1239.     printf("debugger-describe-restarts undefined.\n");
  1240.     return;
  1241.     }
  1242.  
  1243.     if ((thread = CurThread) == NULL) {
  1244.     printf("No current thread.\n");
  1245.     return;
  1246.     }
  1247.  
  1248.     if (thread->status == status_Debuggered)
  1249.     cond = thread->datum;
  1250.     else
  1251.     cond = obj_False;
  1252.  
  1253.     thread_push_escape(thread);
  1254.     set_c_continuation(thread, debugger_cmd_finished);
  1255.     
  1256.     suspend_other_threads(thread);
  1257.     
  1258.     *thread->sp++ = debugger_restarts_var->value;
  1259.     *thread->sp++ = cond;
  1260.     thread_restart(thread);
  1261.     Continue = TRUE;
  1262. }
  1263.  
  1264. static void maybe_return(struct thread *thread, obj_t *vals)
  1265. {
  1266.     if (vals[0] == obj_False) {
  1267.     thread->sp = vals;
  1268.     thread_pop_escape(thread);
  1269.     thread->sp--;
  1270.     pause(pause_DebuggerCommandFinished);
  1271.     }
  1272.     else {
  1273.     obj_t value_vec = vals[1];
  1274.     int len = SOVEC(value_vec)->length;
  1275.     int i;
  1276.     obj_t *old_sp;
  1277.     obj_t keep_going;
  1278.  
  1279.     thread->sp = vals;
  1280.     thread_pop_escape(thread);
  1281.  
  1282.     keep_going = *--thread->sp;
  1283.  
  1284.     thread_buggered(thread);
  1285.  
  1286.     old_sp = pop_linkage(thread);
  1287.  
  1288.     thread->sp = old_sp + len;
  1289.  
  1290.     for (i = 0; i < len; i++)
  1291.         old_sp[i] = SOVEC(value_vec)->contents[i];
  1292.  
  1293.     restart_other_threads(thread);
  1294.  
  1295.     if (keep_going != obj_False)
  1296.         do_return(thread, old_sp, old_sp);
  1297.     else {
  1298.         do_return_setup(thread, old_sp, old_sp);
  1299.         pause(pause_DebuggerCommandFinished);
  1300.     }
  1301.     }
  1302. }
  1303.  
  1304. static void do_restart(obj_t restart)
  1305. {
  1306.     obj_t cond;
  1307.     struct thread *thread;
  1308.  
  1309.     if (debugger_restart_var == NULL
  1310.       || debugger_restart_var->value == obj_Unbound) {
  1311.     printf("debugger-restart undefined.\n");
  1312.     return;
  1313.     }
  1314.  
  1315.     if ((thread = CurThread) == NULL) {
  1316.     printf("No current thread.\n");
  1317.     return;
  1318.     }
  1319.  
  1320.     if (thread->status == status_Debuggered)
  1321.     cond = thread->datum;
  1322.     else
  1323.     cond = obj_False;
  1324.  
  1325.     thread_push_escape(thread);
  1326.     set_c_continuation(thread, maybe_return);
  1327.     
  1328.     suspend_other_threads(thread);
  1329.     
  1330.     *thread->sp++ = debugger_restart_var->value;
  1331.     *thread->sp++ = cond;
  1332.     *thread->sp++ = restart;
  1333.     thread_restart(thread);
  1334.     Continue = TRUE;
  1335. }
  1336.  
  1337. static void restart_cmd(obj_t args)
  1338. {
  1339.     int restart;
  1340.  
  1341.     if ( ! any_args(args))
  1342.     describe_restarts();
  1343.     else if ( ! get_fixnum(first_arg(args), &restart))
  1344.         printf("Bogus restart number, should be an integer.\n");
  1345.     else if (restart < 0)
  1346.         printf("Bogus restart number, should be >= 0.\n");
  1347.     else {
  1348.         should_be_no_args(rest_args(args));
  1349.         do_restart(arg_value(first_arg(args)));
  1350.     }
  1351. }
  1352.  
  1353. static void return_cmd(obj_t args)
  1354. {
  1355.     obj_t cond;
  1356.     struct thread *thread;
  1357.  
  1358.     should_be_no_args(args);
  1359.     if (debugger_return_var == NULL
  1360.       || debugger_return_var->value == obj_Unbound) {
  1361.     printf("debugger-return undefined.\n");
  1362.     return;
  1363.     }
  1364.  
  1365.     if ((thread = CurThread) == NULL) {
  1366.     printf("No current thread.\n");
  1367.     return;
  1368.     }
  1369.  
  1370.     if (thread->status == status_Debuggered)
  1371.     cond = thread->datum;
  1372.     else {
  1373.     printf("The current thread did not call invoke-debugger\n");
  1374.     return;
  1375.     }
  1376.  
  1377.     *thread->sp++ = obj_True;
  1378.  
  1379.     thread_push_escape(thread);
  1380.     set_c_continuation(thread, maybe_return);
  1381.     
  1382.     suspend_other_threads(thread);
  1383.     
  1384.     *thread->sp++ = debugger_return_var->value;
  1385.     *thread->sp++ = cond;
  1386.     thread_restart(thread);
  1387.     Continue = TRUE;
  1388. }
  1389.     
  1390.  
  1391. /* Thread commands. */
  1392.  
  1393. static struct thread *find_thread(obj_t tag)
  1394. {
  1395.     struct thread_list *threads;
  1396.     int id = -1;
  1397.  
  1398.     if (instancep(tag, obj_SymbolClass)) {
  1399.         ;
  1400.     } else if (instancep(tag, obj_FixnumClass)) {
  1401.         id = fixnum_value(tag);
  1402.     } else {
  1403.         printf("Bogus thread identifier: ");
  1404.     print(tag);
  1405.     printf("should be either a symbol or integer.");
  1406.     return NULL;
  1407.     }
  1408.     
  1409.     for (threads = all_threads(); threads != NULL; threads = threads->next) {
  1410.     struct thread *thread = threads->thread;
  1411.     if (THREAD(thread->thread_obj)->debug_name == tag
  1412.      || thread->id == id)
  1413.         return thread;
  1414.     }
  1415.  
  1416.     printf("No thread named ");
  1417.     print(tag);
  1418.     return NULL;
  1419. }
  1420.     
  1421.  
  1422. static void thread_cmd(obj_t args)
  1423. {
  1424.     struct thread_list *threads;
  1425.     struct thread *thread;
  1426.  
  1427.     if ( ! any_args(args)) {
  1428.     for (threads=all_threads(); threads != NULL; threads=threads->next) {
  1429.         if (threads->thread == CurThread)
  1430.         printf("c ");
  1431.         else
  1432.         printf("  ");
  1433.         print_thread(threads->thread);
  1434.     }
  1435.     } else {
  1436.         should_be_no_args(rest_args(args));
  1437.         thread = find_thread(arg_value(first_arg(args)));
  1438.     if (thread != NULL)
  1439.         set_thread(thread);
  1440.     }
  1441. }
  1442.  
  1443. static void kill_cmd(obj_t args)
  1444. {
  1445.     struct thread *thread;
  1446.  
  1447.     if ( ! any_args(args)) {
  1448.     thread = CurThread;
  1449.     if (thread == NULL) {
  1450.         printf("No current thread selected.\n");
  1451.         return;
  1452.     }
  1453.     } else {
  1454.         should_be_no_args(rest_args(args));
  1455.         thread = find_thread(arg_value(first_arg(args)));
  1456.     if (thread == NULL)
  1457.         return;
  1458.     }
  1459.  
  1460.     thread_kill(thread);
  1461.     if (thread == CurThread) {
  1462.     printf("killed the current thread, hence it is no longer current.\n");
  1463.     set_thread(NULL);
  1464.     ThreadChanged = FALSE;
  1465.     FrameChanged = FALSE;
  1466.     }
  1467. }
  1468.     
  1469. static void disable_cmd(obj_t args)
  1470. {
  1471.     struct thread *thread;
  1472.  
  1473.     if ( ! any_args(args)) {
  1474.     thread = CurThread;
  1475.     if (thread == NULL) {
  1476.         printf("No current thread selected.\n");
  1477.         return;
  1478.     }
  1479.     } else {
  1480.         should_be_no_args(rest_args(args));
  1481.         thread = find_thread(arg_value(first_arg(args)));
  1482.     if (thread == NULL)
  1483.         return;
  1484.     }
  1485.  
  1486.     thread_suspend(thread);
  1487.     print_thread(thread);
  1488. }
  1489.     
  1490. static void enable_cmd(obj_t args)
  1491. {
  1492.     struct thread *thread;
  1493.  
  1494.     if ( ! any_args(args)) {
  1495.     thread = CurThread;
  1496.     if (thread == NULL) {
  1497.         printf("No current thread selected.\n");
  1498.         return;
  1499.     }
  1500.     } else {
  1501.         should_be_no_args(rest_args(args));
  1502.         thread = find_thread(arg_value(first_arg(args)));
  1503.     if (thread == NULL)
  1504.         return;
  1505.     }
  1506.  
  1507.     if (thread->suspend_count == 0) {
  1508.     format("thread %= isn't suspended\n", arg_value(first_arg(args)));
  1509.     return;
  1510.     }
  1511.  
  1512.     while (thread->suspend_count > 0)
  1513.     thread_restart(thread);
  1514.     print_thread(thread);
  1515. }
  1516.     
  1517.  
  1518. /* Step/next commands */
  1519.  
  1520. static void step_cmd(obj_t args)
  1521. {
  1522.     struct thread *thread = CurThread;
  1523.  
  1524.     should_be_no_args(args);
  1525.  
  1526.     if (thread == NULL) {
  1527.     printf("No current thread.\n");
  1528.     return;
  1529.     }
  1530.  
  1531.     switch (thread->status) {
  1532.       case status_Running:
  1533.     {
  1534.         enum pause_reason reason;
  1535.         int prev_line = PrevLine;
  1536.  
  1537.         do {
  1538.         reason = single_step(thread);
  1539.         explain_reason(reason);
  1540.         } while (reason == pause_NoReason && CurThread == thread
  1541.              && !FrameChanged && TopFrame->line == prev_line);
  1542.     }
  1543.     break;
  1544.  
  1545.       case status_Debuggered:
  1546.     if (debugger_return_var == NULL
  1547.         || debugger_return_var->value == obj_Unbound) {
  1548.         printf("debugger-return undefined.\n");
  1549.         return;
  1550.     }
  1551.     else {
  1552.         obj_t cond = thread->datum;
  1553.  
  1554.         *thread->sp++ = obj_False;
  1555.  
  1556.         thread_push_escape(thread);
  1557.         set_c_continuation(thread, maybe_return);
  1558.     
  1559.         suspend_other_threads(thread);
  1560.     
  1561.         *thread->sp++ = debugger_return_var->value;
  1562.         *thread->sp++ = cond;
  1563.         thread_restart(thread);
  1564.         Continue = TRUE;
  1565.     }
  1566.  
  1567.     break;
  1568.  
  1569.       default:
  1570.     printf("The current thread is not runnable.\n");
  1571.     return;
  1572.     }
  1573. }
  1574.  
  1575.  
  1576. /* Breakpoint commands */
  1577.  
  1578. static int find_pc_for_line(obj_t component, int line)
  1579. {
  1580.     obj_t debug_info = COMPONENT(component)->debug_info;
  1581.     int len = SOVEC(debug_info)->length;
  1582.     int n_const = COMPONENT(component)->n_constants;
  1583.     int pc = (char *)(&COMPONENT(component)->constant[n_const])
  1584.     - (char *)component;
  1585.     boolean prev_line_before = FALSE;
  1586.     int i;
  1587.     
  1588.     for (i = 0; i < len; i++) {
  1589.     obj_t entry = SOVEC(debug_info)->contents[i];
  1590.     int this_line = fixnum_value(SOVEC(entry)->contents[0]);
  1591.     if (prev_line_before ? line <= this_line : line == this_line)
  1592.         return pc;
  1593.     pc += fixnum_value(SOVEC(entry)->contents[1]);
  1594.     prev_line_before = (this_line != 0 && this_line < line);
  1595.     }
  1596.  
  1597.     return -1;
  1598. }
  1599.  
  1600. static void install_breakpoint(obj_t func, obj_t thing, int line)
  1601. {
  1602.     if (instancep(thing, obj_ComponentClass)) {
  1603.     if (line == -1)
  1604.         printf("Can't install function-start breakpoints directly into "
  1605.            "components.\n");
  1606.     else if (COMPONENT(thing)->debug_info == obj_False) {
  1607.         prin1(func);
  1608.         printf(" has no debug-info.\n");
  1609.     }
  1610.     else {
  1611.         int pc = find_pc_for_line(thing, line);
  1612.  
  1613.         if (pc == -1) {
  1614.         prin1(func);
  1615.         printf(" does not span line number %d\n", line);
  1616.         }
  1617.         else {
  1618.         int id = install_byte_breakpoint(thing, pc);
  1619.         
  1620.         if (id < 0)
  1621.             printf("couldn't install breakpoint in ");
  1622.         else
  1623.             printf("breakpoint %d installed in ", id);
  1624.         prin1(func);
  1625.         printf(" at line %d (pc %d)\n", line, pc);
  1626.         }
  1627.     }
  1628.     }
  1629.     else if (instancep(thing, obj_MethodInfoClass))
  1630.     install_breakpoint(thing, METHOD_INFO(thing)->component, line);
  1631.     else if (!instancep(thing, obj_FunctionClass)) {
  1632.     prin1(thing);
  1633.     printf(" isn't a function, method-info, or component\n");
  1634.     }
  1635.     else if (line == -1) {
  1636.     printf("Can't install function start breakpoints.\n"); /* ### */
  1637.     }
  1638.     else if (!instancep(thing, obj_ByteMethodClass)) {
  1639.     prin1(thing);
  1640.     printf(" isn't a byte method.\n");
  1641.     }
  1642.     else
  1643.     install_breakpoint(func, byte_method_component(thing), line);
  1644. }
  1645.  
  1646. static void breakpoint_cont(struct thread *thread, obj_t *vals)
  1647. {
  1648.     obj_t *old_sp;
  1649.     obj_t okay = vals[0];
  1650.     int line = fixnum_value(thread->fp[0]);
  1651.  
  1652.     if (okay != obj_False) {
  1653.     obj_t results = vals[1];
  1654.     obj_t thing = obj_False;
  1655.  
  1656.     if (SOVEC(results)->length != 0)
  1657.         thing = SOVEC(results)->contents[0];
  1658.  
  1659.     install_breakpoint(thing, thing, line);
  1660.     }
  1661.     old_sp = pop_linkage(thread);
  1662.     do_return(thread, old_sp, old_sp);
  1663. }
  1664.  
  1665. static void breakpoint_cmd(obj_t args)
  1666. {
  1667.     obj_t exprs = args;
  1668.     
  1669.     if ( ! any_args(exprs))
  1670.     list_breakpoints();
  1671.     else {
  1672.     boolean okay = TRUE;
  1673.     boolean func_simple = TRUE;
  1674.     obj_t line;
  1675.  
  1676.     eval_vars(first_arg(exprs), &okay, &func_simple);
  1677.  
  1678.     if (!okay)
  1679.         return;
  1680.  
  1681.     if (TAIL(exprs) == obj_Nil)
  1682.         line = make_fixnum(-1);
  1683.     else if (TAIL(TAIL(exprs)) == obj_Nil) {
  1684.         boolean line_simple = TRUE;
  1685.  
  1686.         eval_vars(HEAD(TAIL(exprs)), &okay, &line_simple);
  1687.  
  1688.         if (!okay)
  1689.         return;
  1690.  
  1691.         line = TAIL(HEAD(TAIL(exprs)));
  1692.         if (!line_simple || !obj_is_fixnum(line)) {
  1693.         printf("Bogus line number.\n");
  1694.         return;
  1695.         }
  1696.     }
  1697.     else {
  1698.         printf("Too many arguments to breakpoint.\n");
  1699.         return;
  1700.     }
  1701.  
  1702.     if (func_simple) {
  1703.         obj_t func = TAIL(HEAD(exprs));
  1704.         install_breakpoint(func, func, fixnum_value(line));
  1705.     }
  1706.     else if (debugger_eval_var == NULL
  1707.          || debugger_eval_var->value == obj_Unbound)
  1708.         printf("Can't eval expressions without debugger-eval "
  1709.            "being defined.\n");
  1710.     else {
  1711.         struct thread *thread = CurThread;
  1712.  
  1713.         if (thread == NULL) {
  1714.         thread
  1715.             = thread_create(make_byte_string("eval for disassemble"));
  1716.         set_c_continuation(thread, kill_me);
  1717.         }
  1718.         else {
  1719.         thread_push_escape(thread);
  1720.         set_c_continuation(thread, debugger_cmd_finished);
  1721.         }
  1722.  
  1723.         suspend_other_threads(thread);
  1724.  
  1725.         *thread->sp++ = obj_False;
  1726.         push_linkage(thread, thread->sp);
  1727.         set_c_continuation(thread, breakpoint_cont);
  1728.         *thread->sp++ = line;
  1729.         thread->datum = obj_rawptr(thread->sp);
  1730.         *thread->sp++ = debugger_eval_var->value;
  1731.         *thread->sp++ = HEAD(exprs);
  1732.  
  1733.         thread_restart(thread);
  1734.  
  1735.         Continue = TRUE;
  1736.     }
  1737.     }
  1738. }
  1739.  
  1740. static void delete_cmd(obj_t args)
  1741. {
  1742.     int num;
  1743.     while (any_args(args)) {
  1744.         if ( ! get_fixnum(first_arg(args), &num))
  1745.         printf("Bogus breakpoint id\n");
  1746.     else
  1747.         remove_breakpoint(num);
  1748.     args = rest_args(args);
  1749.     }
  1750. }
  1751.  
  1752.  
  1753. /* Disassemble command */
  1754.  
  1755. static struct byteop_info {
  1756.     int match;
  1757.     int mask;
  1758.     char *op;
  1759. } ByteOpInfos[] = {
  1760.     {op_TRAP, 0xff, "trap"},
  1761.     {op_BREAKPOINT, 0xff, "breakpoint"},
  1762.     {op_RETURN_SINGLE, 0xff, "return single"},
  1763.     {op_MAKE_VALUE_CELL, 0xff, "make-value-cell"},
  1764.     {op_VALUE_CELL_REF, 0xff, "value-cell-ref"},
  1765.     {op_VALUE_CELL_SET, 0xff, "value-cell-set"},
  1766.     {op_MAKE_METHOD, 0xff, "make-method"},
  1767.     {op_CHECK_TYPE, 0xff, "check-type"},
  1768.     {op_CHECK_TYPE_FUNCTION, 0xff, "check-type-function"},
  1769.     {op_CANONICALIZE_VALUE, 0xff, "canonicalize-value %r"},
  1770.     {op_PUSH_BYTE, 0xff, "push\t%b"},
  1771.     {op_PUSH_INT, 0xff, "push\t%i"},
  1772.     {op_CONDITIONAL_BRANCH, 0xff, "cbr\t%t"},
  1773.     {op_BRANCH, 0xff, "br\t%t"},
  1774.     {op_PUSH_NIL, 0xff, "push\t#()"},
  1775.     {op_PUSH_UNBOUND, 0xff, "push\t#unbound"},
  1776.     {op_PUSH_TRUE, 0xff, "push\t#t"},
  1777.     {op_PUSH_FALSE, 0xff, "push\t#f"},
  1778.     {op_DUP, 0xff, "dup"},
  1779.     {op_DOT_TAIL, 0xff, "dot\ttail"},
  1780.     {op_DOT_FOR_MANY, 0xff, "dot\tfor %r"},
  1781.     {op_DOT_FOR_SINGLE, 0xff, "dot\tfor single"},
  1782.  
  1783.     {op_PUSH_CONSTANT, 0xf0, "push\tconst(%c)\t"},
  1784.     {op_PUSH_ARG, 0xf0, "push\targ(%a)"},
  1785.     {op_POP_ARG, 0xf0, "pop\targ(%a)"},
  1786.     {op_PUSH_LOCAL, 0xf0, "push\tlocal(%a)"},
  1787.     {op_POP_LOCAL, 0xf0, "pop\tlocal(%a)"},
  1788.     {op_CALL_TAIL, 0xf0, "call\tnargs = %a, tail"},
  1789.     {op_CALL_FOR_MANY, 0xf0, "call\tnargs = %n, for %r"},
  1790.     {op_CALL_FOR_SINGLE, 0xf0, "call\tnargs = %n, for single"},
  1791.     {op_PUSH_VALUE, 0xf0, "push\tvalue %v"},
  1792.     {op_PUSH_FUNCTION, 0xf0, "push\tfunction %v"},
  1793.     {op_POP_VALUE, 0xf0, "pop\tvalue %v"},
  1794.  
  1795.     {op_PLUS, 0xff, "+"},
  1796.     {op_MINUS, 0xff, "-"},
  1797.     {op_LT, 0xff, "<"},
  1798.     {op_LE, 0xff, "<="},
  1799.     {op_EQ, 0xff, "="},
  1800.     {op_IDP, 0xff, "=="},
  1801.     {op_NE, 0xff, "~="},
  1802.     {op_GE, 0xff, ">="},
  1803.     {op_GT, 0xff, ">"},
  1804.     {0, 0, NULL}
  1805. };
  1806.  
  1807. static int disassem_int4(unsigned char *ptr)
  1808. {
  1809.     return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
  1810. }
  1811.  
  1812. static unsigned char *disassemble_op(obj_t component, unsigned char *start)
  1813. {
  1814.     unsigned char *ptr = start;
  1815.     unsigned char byte = *ptr++;
  1816.     struct byteop_info *info;
  1817.     char buf[256], *fill = buf, *msg = "";
  1818.     int i, c;
  1819.     obj_t trailer = NULL;
  1820.     boolean extra = FALSE;
  1821.  
  1822.     for (info = ByteOpInfos; info->op != NULL; info++)
  1823.     if ((info->mask & byte) == info->match) {
  1824.         msg = info->op;
  1825.         break;
  1826.     }
  1827.  
  1828.     do {
  1829.     c = *msg++;
  1830.     if (c == '%') {
  1831.         switch (*msg++) {
  1832.           case 'a':
  1833.         i = byte & 0xf;
  1834.         if (i == 0xf) {
  1835.             i = *ptr++;
  1836.             if (i == 0xff) {
  1837.             i = disassem_int4(ptr);
  1838.             ptr += 4;
  1839.             }
  1840.         }
  1841.         sprintf(fill, "%d", i);
  1842.         break;
  1843.  
  1844.           case 'b':
  1845.         sprintf(fill, "%d", *(signed char *)(ptr++));
  1846.         break;
  1847.  
  1848.           case 'c':
  1849.         i = byte & 0xf;
  1850.         if (i == 0xf) {
  1851.             i = *ptr++;
  1852.             if (i == 0xff) {
  1853.             i = disassem_int4(ptr);
  1854.             ptr += 4;
  1855.             }
  1856.         }
  1857.         sprintf(fill, "%d", i);
  1858.         trailer = COMPONENT(component)->constant[i];
  1859.         break;
  1860.  
  1861.           case 'i':
  1862.         sprintf(fill, "%d", disassem_int4(ptr));
  1863.         ptr += 4;
  1864.         break;
  1865.  
  1866.           case 'n':
  1867.         i = byte & 0xf;
  1868.         if (i == 0xf) {
  1869.             extra = TRUE;
  1870.             i = *ptr++;
  1871.             if (i == 0xff) {
  1872.             i = disassem_int4(ptr);
  1873.             ptr += 4;
  1874.             }
  1875.         }
  1876.         sprintf(fill, "%d", i);
  1877.         break;
  1878.  
  1879.           case 'r':
  1880.         i = *ptr++;
  1881.         if (i == 0xff) {
  1882.             i = disassem_int4(ptr);
  1883.             ptr += 4;
  1884.         }
  1885.         sprintf(fill, "%d", i>>1);
  1886.         if (i & 1)
  1887.             strcat(fill, ", #rest");
  1888.         break;
  1889.  
  1890.           case 't':
  1891.         ptr += 4;
  1892.         sprintf(fill, "%d",
  1893.             (int) (ptr - (unsigned char *)component
  1894.                    + disassem_int4(ptr-4)));
  1895.         break;
  1896.  
  1897.           case 'v':
  1898.         i = byte & 0xf;
  1899.         if (i == 0xf) {
  1900.             i = *ptr++;
  1901.             if (i == 0xff) {
  1902.             i = disassem_int4(ptr);
  1903.             ptr += 4;
  1904.             }
  1905.         }
  1906.         trailer = ((struct variable *)COMPONENT(component)
  1907.                ->constant[i])
  1908.             ->name;
  1909.         fill[0] = '\0';
  1910.         break;
  1911.  
  1912.           default:
  1913.         fill[0] = '?';
  1914.         fill[1] = '?';
  1915.         fill[2] = '?';
  1916.         fill[3] = '\0';
  1917.         }
  1918.         fill = strchr(fill, '\0');
  1919.     }
  1920.     else
  1921.         *fill++ = c;
  1922.     } while (c != '\0');
  1923.  
  1924.     if (extra)
  1925.     ptr++;
  1926.  
  1927.     for (i = 0; i < (ptr - start); i++)
  1928.     printf(" %02x", start[i]);
  1929.     while (i++ < 4)
  1930.     printf("   ");
  1931.     printf("\t%s", buf);
  1932.     if (trailer != NULL)
  1933.     prin1(trailer);
  1934.  
  1935.     return ptr;
  1936. }
  1937.  
  1938. static void disassemble_component(obj_t component)
  1939. {
  1940.     obj_t debug_name = COMPONENT(component)->debug_name;
  1941.     obj_t debug_info = COMPONENT(component)->debug_info;
  1942.     obj_t source_file = COMPONENT(component)->source_file;
  1943.     obj_t mtime = COMPONENT(component)->mtime;
  1944.     int nconst = COMPONENT(component)->n_constants;
  1945.     unsigned char *ptr
  1946.     = (unsigned char *)(COMPONENT(component)->constant + nconst);
  1947.     unsigned char *end
  1948.     = obj_ptr(unsigned char *, component) + COMPONENT(component)->length;
  1949.     int debug_index = 0;
  1950.     unsigned char *next_line;
  1951.     int i;
  1952.  
  1953.     if (debug_name == obj_False)
  1954.     printf("anonymous");
  1955.     else
  1956.     prin1(debug_name);
  1957.     printf(" component");
  1958.     if (source_file != obj_False) {
  1959.     printf(", from ");
  1960.     prin1(source_file);
  1961.     }
  1962.  
  1963.     if (debug_info == obj_False)
  1964.     next_line = end;
  1965.     else
  1966.     next_line = ptr;
  1967.  
  1968.     while (ptr < end) {
  1969.     while (ptr >= next_line) {
  1970.         obj_t entry = SOVEC(debug_info)->contents[debug_index++];
  1971.         int line = fixnum_value(SOVEC(entry)->contents[0]);
  1972.         if (line != 0) {
  1973.         FILE *source = find_source_line(source_file, mtime, line);
  1974.         if (source) {
  1975.             int c;
  1976.             printf("\n%d\t", line);
  1977.             while ((c = getc(source)) != EOF && c != '\n')
  1978.             putchar(c);
  1979.         }
  1980.         else
  1981.             printf("\nline %d:", line);
  1982.         }
  1983.         next_line += fixnum_value(SOVEC(entry)->contents[1]);
  1984.     }
  1985.     printf("\n%6d:", (int)(ptr - (unsigned char *)component));
  1986.     ptr = disassemble_op(component, ptr);
  1987.     }
  1988.     putchar('\n');
  1989.  
  1990.     for (i = 0; i < nconst; i++) {
  1991.     obj_t c = COMPONENT(component)->constant[i];
  1992.     if (instancep(c, obj_MethodInfoClass)) {
  1993.         putchar('\n');
  1994.         prin1(c);
  1995.         printf(", ");
  1996.         disassemble_component(METHOD_INFO(c)->component);
  1997.     }
  1998.     }
  1999. }
  2000.  
  2001. static void disassemble_thing(obj_t thing)
  2002. {
  2003.     if (instancep(thing, obj_ComponentClass))
  2004.     disassemble_component(thing);
  2005.     else if (instancep(thing, obj_ByteMethodClass))
  2006.     disassemble_component(byte_method_component(thing));
  2007.     else if (instancep(thing, obj_FunctionClass)) {
  2008.     printf("don't know how to disassemble ");
  2009.     print(thing);
  2010.     }
  2011.     else {
  2012.     prin1(thing);
  2013.     printf(" isn't a function or component\n");
  2014.     }
  2015. }
  2016.  
  2017. static void disassemble_cont(struct thread *thread, obj_t *vals)
  2018. {
  2019.     obj_t *old_sp;
  2020.     obj_t okay = vals[0];
  2021.  
  2022.     if (okay != obj_False) {
  2023.     obj_t results = vals[1];
  2024.     if (SOVEC(results)->length == 0)
  2025.         disassemble_thing(obj_False);
  2026.     else
  2027.         disassemble_thing(SOVEC(results)->contents[0]);
  2028.     }
  2029.     old_sp = pop_linkage(thread);
  2030.     do_return(thread, old_sp, old_sp);
  2031. }
  2032.  
  2033. static void disassemble_cmd(obj_t args)
  2034. {
  2035.     obj_t exprs = args;
  2036.  
  2037.     if (exprs == obj_Nil) {
  2038.     if (CurFrame == NULL)
  2039.         printf("No current frame.\n");
  2040.     else if (obj_is_fixnum(CurFrame->component))
  2041.         printf("Current frame is not in a byte method\n");
  2042.     else
  2043.         disassemble_component(CurFrame->component);
  2044.     }
  2045.     else if (TAIL(exprs) != obj_Nil)
  2046.     printf("Too many expressions for disassemble\n");
  2047.     else {
  2048.     boolean okay = TRUE;
  2049.     boolean simple = TRUE;
  2050.  
  2051.     eval_vars(HEAD(exprs), &okay, &simple);
  2052.  
  2053.     if (!okay)
  2054.         return;
  2055.  
  2056.     if (simple)
  2057.         disassemble_thing(TAIL(HEAD(exprs)));
  2058.     else if (debugger_eval_var == NULL
  2059.          || debugger_eval_var->value == obj_Unbound)
  2060.         printf("Can't eval expressions without debugger-eval "
  2061.            "being defined.\n");
  2062.     else {
  2063.         struct thread *thread = CurThread;
  2064.  
  2065.         if (thread == NULL) {
  2066.         thread
  2067.             = thread_create(make_byte_string("eval for disassemble"));
  2068.         set_c_continuation(thread, kill_me);
  2069.         }
  2070.         else {
  2071.         thread_push_escape(thread);
  2072.         set_c_continuation(thread, debugger_cmd_finished);
  2073.         }
  2074.  
  2075.         suspend_other_threads(thread);
  2076.  
  2077.         *thread->sp++ = obj_False;
  2078.         push_linkage(thread, thread->sp);
  2079.         set_c_continuation(thread, disassemble_cont);
  2080.         thread->datum = obj_rawptr(thread->sp);
  2081.         *thread->sp++ = debugger_eval_var->value;
  2082.         *thread->sp++ = HEAD(exprs);
  2083.  
  2084.         thread_restart(thread);
  2085.  
  2086.         Continue = TRUE;
  2087.     }
  2088.     }
  2089. }
  2090.  
  2091.  
  2092. /* Describe command. */
  2093.  
  2094. static void describe_cont(struct thread *thread, obj_t *vals)
  2095. {
  2096.     obj_t *old_sp;
  2097.     obj_t okay = vals[0];
  2098.  
  2099.     if (okay != obj_False) {
  2100.     obj_t results = vals[1];
  2101.     if (SOVEC(results)->length == 0)
  2102.         describe(obj_False);
  2103.     else
  2104.         describe(SOVEC(results)->contents[0]);
  2105.     }
  2106.     old_sp = pop_linkage(thread);
  2107.     do_return(thread, old_sp, old_sp);
  2108. }
  2109.  
  2110. static void describe_cmd(obj_t args)
  2111. {
  2112.     obj_t exprs = args;
  2113.  
  2114.     if (exprs == obj_False)
  2115.     printf("Invalid expression.\n");
  2116.     else if (exprs == obj_Nil)
  2117.     printf("Describe what?\n");
  2118.     else if (TAIL(exprs) != obj_Nil)
  2119.     printf("too many things to describe, one at most.\n");
  2120.     else {
  2121.     boolean okay = TRUE;
  2122.     boolean simple = TRUE;
  2123.  
  2124.     eval_vars(HEAD(exprs), &okay, &simple);
  2125.  
  2126.     if (!okay)
  2127.         return;
  2128.  
  2129.     if (simple)
  2130.         describe(TAIL(HEAD(exprs)));
  2131.     else if (debugger_eval_var == NULL
  2132.          || debugger_eval_var->value == obj_Unbound)
  2133.         printf("Can't eval expressions without debugger-eval "
  2134.            "being defined.\n");
  2135.     else {
  2136.         struct thread *thread = CurThread;
  2137.  
  2138.         if (thread == NULL) {
  2139.         thread
  2140.             = thread_create(make_byte_string("eval for disassemble"));
  2141.         set_c_continuation(thread, kill_me);
  2142.         }
  2143.         else {
  2144.         thread_push_escape(thread);
  2145.         set_c_continuation(thread, debugger_cmd_finished);
  2146.         }
  2147.  
  2148.         suspend_other_threads(thread);
  2149.  
  2150.         *thread->sp++ = obj_False;
  2151.         push_linkage(thread, thread->sp);
  2152.         set_c_continuation(thread, describe_cont);
  2153.         thread->datum = obj_rawptr(thread->sp);
  2154.         *thread->sp++ = debugger_eval_var->value;
  2155.         *thread->sp++ = HEAD(exprs);
  2156.  
  2157.         thread_restart(thread);
  2158.  
  2159.         Continue = TRUE;
  2160.     }
  2161.     }
  2162. }
  2163.  
  2164.  
  2165.  
  2166. /* Command table. */
  2167.  
  2168. static struct cmd_entry Cmds[] = {
  2169.     {"abort", "abort\t\tInvoke the first available <abort> restart.",
  2170.      abort_cmd},
  2171.     {"backtrace",
  2172.      "backtrace\tDisplay a stack backtrace for the current thread.",
  2173.      backtrace_cmd},
  2174.     {"breakpoint", "breakpoint\tInstall a breakpoint.", breakpoint_cmd},
  2175.     {"c", NULL, continue_cmd},
  2176.     {"call", "call expr...\tCall each expr, printing the results.", call_cmd},
  2177.     {"continue", "continue\tContinue execution.", continue_cmd},
  2178.     {"d", NULL, down_cmd},
  2179.     {"delete", "delete id\tDelete the given breakpoint.", delete_cmd},
  2180.     {"describe", "describe inst\tDescribe the slots instance.", describe_cmd},
  2181.     {"disable", "disable thread\tSuspend the given thread.", disable_cmd},
  2182.     {"disassemble",
  2183.      "disassemble\tDisassemble the component for the current frame",
  2184.      disassemble_cmd},
  2185.     {"down", "down\t\tMove down one frame.", down_cmd},
  2186.     {"enable", "enable thread\tRestart the given thread.", enable_cmd},
  2187.     {"error",
  2188. "error\t\tRedisplay the error that caused this thread to enter the debugger.",
  2189.      error_cmd},
  2190.     {"flush", "flush\t\tFlush all debugger variables.", flush_cmd},
  2191.     {"frame", "frame [num]\tMove to the given frame.", frame_cmd},
  2192.     {"gc", "gc\t\tCollect garbage.", gc_cmd},
  2193.     {"help", "help [topic]\tDisplay help about some topic.", help_cmd},
  2194.     {"kill", "kill thread\tKill the given thread.", kill_cmd},
  2195.     {"l", NULL, locals_cmd},
  2196.     {"library",
  2197.      "library [lib]\tSwitch to given library or list all libraries.",
  2198.      library_cmd},
  2199.     {"locals", "locals\t\tDisplay all the locals in the current frame.",
  2200.      locals_cmd},
  2201.     {"module",
  2202.  "module [module]\tSwitch to given module or list modules in current library.",
  2203.      module_cmd},
  2204.     {"print", "print expr...\tPrint each expr, ignoring errors.", print_cmd},
  2205.     {"restart", "restart [num]\tList or invoke one of the available restarts.",
  2206.      restart_cmd},
  2207.     {"return",
  2208.      "return\t\tReturn from this call to invoke-debugger (if allowed)",
  2209.      return_cmd},
  2210.     {"step", "step\t\tStep the current thread one byte-op.", step_cmd},
  2211.     {"thread", "thread [name]\tSwitch to given thread or list all threads.",
  2212.      thread_cmd},
  2213.     {"troff", "troff\t\tTurn function/return tracing off.", troff_cmd},
  2214.     {"tron", "tron\t\tTurn function/return tracing on.", tron_cmd},
  2215.     {"up", "up\t\tMove up one frame.", up_cmd},
  2216.     {"quit", "quit\t\tQuit.", quit_cmd},
  2217.     {NULL, NULL, NULL}
  2218. };
  2219.     
  2220. static void help_cmd(obj_t args)
  2221. {
  2222.     struct cmd_entry *ptr;
  2223.  
  2224.     if ( ! any_args(args)) {
  2225.         for (ptr = Cmds; ptr->cmd != NULL; ptr++)
  2226.         if (ptr->help)
  2227.             printf("%s\n", ptr->help);
  2228.     } else {
  2229.         while (any_args(args)) {
  2230.         char *name;
  2231.  
  2232.         if ( ! get_name(first_arg(args), &name)) {
  2233.             printf("Bogus command name: ");
  2234.         print(arg_value(first_arg(args)));
  2235.         } else {
  2236.             for (ptr = Cmds; ptr->cmd != NULL; ptr++)
  2237.             if (strncasecmp(name, ptr->cmd, strlen(name)) == 0)
  2238.                 if (ptr->help) 
  2239.                 printf("%s\n", ptr->help);
  2240.         }
  2241.         args = rest_args(args);
  2242.     }
  2243.     }
  2244. }
  2245.  
  2246. static void do_cmd(obj_t command)
  2247. {
  2248.     if (command == obj_Nil)
  2249.         ;
  2250.     else if (instancep(command, obj_ByteStringClass))
  2251.       printf("%s\n", string_chars(command));
  2252.     else {
  2253.         struct cmd_entry *entry = find_cmd(HEAD(command), Cmds, "command");
  2254.         if (entry && entry->fn)
  2255.         (*entry->fn)(TAIL(command));
  2256.     }
  2257. }
  2258.  
  2259.  
  2260. /* The main debugger loop */
  2261.  
  2262. static void maybe_print_frame(void)
  2263. {
  2264.     if (ThreadChanged) {
  2265.     ThreadChanged = FALSE;
  2266.  
  2267.     if (CurThread == NULL) {
  2268.         printf("no current thread\n");
  2269.         FrameChanged = FALSE;
  2270.     }
  2271.     else {
  2272.         printf("thread ");
  2273.         print_thread(CurThread);
  2274.         FrameChanged = TRUE;
  2275.     }
  2276.     }
  2277.  
  2278.     if (FrameChanged) {
  2279.     if (CurFrame == NULL)
  2280.         printf("No stack.\n");
  2281.     else
  2282.         print_frame(CurFrame, FALSE);
  2283.     FrameChanged = FALSE;
  2284.     PrevLine = -1;
  2285.     }
  2286.  
  2287.     if (CurFrame != NULL
  2288.       && CurFrame->source_file != obj_False
  2289.       && CurFrame->line != PrevLine) {
  2290.     printf("%s", string_chars(CurFrame->source_file));
  2291.     if (CurFrame->line != 0) {
  2292.         int line = CurFrame->line;
  2293.         FILE *source = find_source_line(CurFrame->source_file,
  2294.                         CurFrame->mtime,
  2295.                         line);
  2296.         if (source) {
  2297.         int c;
  2298.         printf("\n%d\t", line);
  2299.         while ((c = getc(source)) != EOF && c <= ' ')
  2300.             ;
  2301.         while (c != EOF && c != '\n') {
  2302.             putchar(c);
  2303.             c = getc(source);
  2304.         }
  2305.         putchar('\n');
  2306.         }
  2307.         else
  2308.         printf(", line %d.\n", line);
  2309.     }
  2310.     else
  2311.         putchar('\n');
  2312.     PrevLine = CurFrame->line;
  2313.     }
  2314. }
  2315.  
  2316. static void blow_off_cmd(void)
  2317. {
  2318.  
  2319.     longjmp(BlowOffCmd, TRUE);
  2320. }
  2321.  
  2322. void invoke_debugger(enum pause_reason reason)
  2323. {
  2324.     extern obj_t parse_command(FILE *input);
  2325.  
  2326.     Continue = FALSE;
  2327.  
  2328.     explain_reason(reason);
  2329.  
  2330.     while (Continue) {
  2331.     Continue = FALSE;
  2332.     reason = do_stuff();
  2333.     explain_reason(reason);
  2334.     }
  2335.  
  2336.     if ( ! isatty(fileno(stdin))
  2337.       && ! freopen("/dev/tty", "r", stdin)) {
  2338.         printf("STDIN is not a tty and cannot open /dev/tty.  Cannot debug.\n");
  2339.     exit(1);
  2340.     }
  2341.  
  2342.     while (1) {
  2343.     thread_set_current(NULL);
  2344.  
  2345.     while (!Continue) {
  2346.  
  2347.         maybe_print_frame();
  2348.  
  2349.         if (setjmp(BlowOffCmd)) {
  2350.             printf("\ninterrupted\n");
  2351.         unblock_interrupt_handler();
  2352.         } else
  2353.             set_interrupt_handler(blow_off_cmd);
  2354.  
  2355.         printf("mindy> ");
  2356.         fflush(stdout);
  2357.  
  2358.         do_cmd(parse_command(stdin));
  2359.  
  2360.         if (feof(stdin))
  2361.             quit_cmd(obj_Nil);
  2362.     }
  2363.  
  2364.     Continue = FALSE;
  2365.  
  2366.     reason = do_stuff();
  2367.     explain_reason(reason);
  2368.     }
  2369. }
  2370.  
  2371.  
  2372. /* GC stuff. */
  2373.  
  2374. void scavenge_debug_roots(void)
  2375. {
  2376.     scavenge(&do_print_func);
  2377.     scavenge(&do_eval_func);
  2378.     scavenge(&cur_source_file);
  2379.     scav_frames(TopFrame);
  2380.     if (CurThreadObj)
  2381.     scavenge(&CurThreadObj);
  2382. }
  2383.  
  2384.  
  2385. /* Initialization stuff. */
  2386.  
  2387. void init_debug_functions(void)
  2388. {
  2389.     cur_source_file = obj_False;
  2390.     do_print_func = make_raw_function("debug-print", 1, FALSE, obj_False,
  2391.                       FALSE, obj_Nil, obj_ObjectClass,
  2392.                       do_print_start);
  2393.     do_eval_func = make_raw_function("debug-eval", 1, FALSE, obj_False,
  2394.                      FALSE, obj_Nil, obj_ObjectClass,
  2395.                      do_eval_start);
  2396.     debugger_eval_var = find_variable(module_BuiltinStuff,
  2397.                       symbol("debugger-eval"),
  2398.                       FALSE, TRUE);
  2399.     debugger_flush_var = find_variable(module_BuiltinStuff,
  2400.                       symbol("debugger-flush"),
  2401.                       FALSE, TRUE);
  2402.     debugger_call_var = find_variable(module_BuiltinStuff,
  2403.                       symbol("debugger-call"),
  2404.                       FALSE, TRUE);
  2405.     debugger_print_var = find_variable(module_BuiltinStuff,
  2406.                        symbol("debugger-print"),
  2407.                        FALSE, TRUE);
  2408.     debugger_report_var = find_variable(module_BuiltinStuff,
  2409.                     symbol("debugger-report-condition"),
  2410.                     FALSE, TRUE);
  2411.     debugger_abort_var = find_variable(module_BuiltinStuff,
  2412.                        symbol("debugger-abort"),
  2413.                        FALSE, TRUE);
  2414.     debugger_restarts_var = find_variable(module_BuiltinStuff,
  2415.                       symbol("debugger-describe-restarts"),
  2416.                       FALSE, TRUE);
  2417.     debugger_restart_var = find_variable(module_BuiltinStuff,
  2418.                      symbol("debugger-restart"),
  2419.                      FALSE, TRUE);
  2420.     debugger_return_var = find_variable(module_BuiltinStuff,
  2421.                     symbol("debugger-return"),
  2422.                     FALSE, TRUE);
  2423. }
  2424.